package cate.game.pvp.pointrace.handler;

import cate.common.util.XT;
import cate.game.opponent.SectionIndex;
import cate.game.pvp.pointrace.data.PointRaceOpponent;
import cate.game.pvp.pointrace.data.PointRacePs;
import cate.game.pvp.pointrace.data.PointRacePsData;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static cate.game.pvp.pointrace.data.PointRacePs.INDEX_ROBOT;

@Slf4j
public class BothPointRaceOpQuery implements PointRaceOpQuery {

    private final PointRacePsData psData;

    public BothPointRaceOpQuery(Supplier<PointRacePsData> psDataSupplier) {
        Objects.requireNonNull(psDataSupplier);
        this.psData = Objects.requireNonNull(psDataSupplier.get());
    }

    @Override
    public List<PointRaceOpponent> query(QueryParam param) {

        Map<String, PointRacePs> playIndexMap = psData.getIndex(PointRacePs.INDEX_PLAYER);
        int needPlayers = param.getLimit();
        Map<String, PointRaceOpponent> opponentMap = new HashMap<>(needPlayers);

        Collection<PointRacePs> sortedOpponents = playIndexMap.values()
                .stream()
                .filter(ps -> !StringUtils.equalsIgnoreCase(ps.getOpponent().getSnapshot().uid, param.getUid()))
                .sorted(Comparator.comparingLong(eps -> eps.getOpponent().getPoints()))
                .collect(Collectors.toList());

        List<PointRaceOpponent> higherList = sortedOpponents.stream()
                .map(PointRacePs::getOpponent)
                .filter(opponent -> opponent.getPoints() > param.getPoints())
                .collect(Collectors.toList());

        if (higherList.size() > 1) {
            Collections.shuffle(higherList);
        }

        higherList.stream()
                .findFirst()
                .ifPresent(op -> opponentMap.put(op.getSnapshot().uid, op));


        List<PointRaceOpponent> oppList = sortedOpponents.stream()
                .map(PointRacePs::getOpponent)
                .filter(opp -> !opponentMap.containsKey(opp.getSnapshot().uid))
                .collect(Collectors.toList());

        oppList.addAll(psData.getIndex(INDEX_ROBOT)
                .values()
                .stream()
                .map(PointRacePs::getOpponent)
                .collect(Collectors.toList()));

        oppList.sort(Comparator.comparing(PointRaceOpponent::getPoints));
        long[] valArr = new long[oppList.size()];
        for (int i = 0; i < oppList.size(); i++) {
            valArr[i] = oppList.get(i).getPoints();
        }
        SectionIndex si = new SectionIndex(valArr, param.getPoints(), 20);
        List<PointRaceOpponent> candidate = new ArrayList<>();
        for (int i = 0; i < oppList.size(); i++) {
            if (i >= si.indexBeg && i <= si.indexEnd) {
                candidate.add(oppList.get(i));
            }
        }

        needPlayers -= opponentMap.size();

        XT.randomPick(candidate, needPlayers, false)
                .forEach(opp -> opponentMap.put(opp.getSnapshot().uid, opp));

        return Lists.newArrayList(opponentMap.values());

//        List<PointRaceOpponent> lowerOppList = sortedOpponents.stream()
//                .filter(ps -> !StringUtils.equalsIgnoreCase(ps.getUid(), param.getUid()))
//                .map(PointRacePs::getOpponent)
//                .filter(opponent -> opponent.getPoints() <= param.getPoints())
//                .collect(Collectors.toList());
//
//        Collections.shuffle(lowerOppList);
//
//        lowerOppList.stream()
//                .limit(needPlayers)
//                .forEach(opponent -> opponentMap.put(opponent.getSnapshot().uid, opponent));


//        if (!findHigherRealOpp && opponentMap.size() < param.getLimit()) {
//            Map<String, PointRacePs> robotIndexMap = psData.getIndex(PointRacePs.INDEX_ROBOT);
//            robotIndexMap.values()
//                    .stream()
//                    .map(PointRacePs::getOpponent)
//                    .filter(opponent -> opponent.getPoints() > param.getPoints())
//                    .findFirst()
//                    .ifPresent(opponent -> opponentMap.put(opponent.getSnapshot().uid, opponent));
//        }
//
//        int needRobots = param.getLimit() - opponentMap.size();
//
//        if (needRobots > 0) {
//            Map<String, PointRacePs> robotIndexMap = psData.getIndex(PointRacePs.INDEX_ROBOT);
//            List<PointRaceOpponent> robotList = robotIndexMap.values()
//                    .stream()
//                    .sorted(Comparator.comparingLong(opponent -> -opponent.getOpponent().getPoints()))
//                    .map(PointRacePs::getOpponent)
//                    .filter(opponent -> opponent.getPoints() <= param.getPoints())
//                    .limit(20)
//                    .collect(Collectors.toList());
//            Collections.shuffle(robotList);
//            robotList.stream()
//                    .limit(needRobots)
//                    .forEach(op -> opponentMap.put(op.getSnapshot().uid, op));
//        }
    }

}
